/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			mdiimpl.cc
  \date			Dec 2012
  \author		TNick

  \brief		Contains the implementation of MdiImpl class


*//*


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read COPYING and README files in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<cpg/cpg.h>

#include	<cpg/actions/actionshost.h>
#include	<cpg/actions/editorbase.h>
#include	<cpg/actions/mdicontainer.h>
#include	"mdiimpl.h"
#include	<QMenu>
#include	<QToolBar>
#include	<QMdiArea>
#include    <QMdiSubWindow>
#include    <QFileDialog>
#include    <QMessageBox>


/*  INCLUDES    ============================================================ */
//
//
//
//
/*  DEFINITIONS    --------------------------------------------------------- */


/*  DEFINITIONS    ========================================================= */
//
//
//
//
/*  DATA    ---------------------------------------------------------------- */

/*  DATA    ================================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
MdiImpl::MdiImpl		( QObject * parent )
	:QObject( parent ), MemTrack()
{
	PGDBG2( PGDBG_CTORDTOR, "Creating 			MdiImpl", this );
	host_ = NULL;
	mdi_area_ = NULL;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
MdiImpl::~MdiImpl	( void )
{
	PGDBG2( PGDBG_CTORDTOR, "Destroyng 			MdiImpl", this );
	/* stub */
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool			MdiImpl::init				(
		ActionsHost * host, QMdiArea * mdi_area )
{
	PGDBG2( PGDBG_A_MDI, "MdiImpl: init", this );

	host_ = host;
	mdi_area_ = mdi_area;
	ui_.setupUi( host->uiParentWidget() );

	/* basic interaction with mdi childs */
	connect(ui_.action_Tile, SIGNAL(triggered()),
			mdi_area_, SLOT(tileSubWindows()));
	connect(ui_.action_Cascade, SIGNAL(triggered()),
			mdi_area_, SLOT(cascadeSubWindows()));
	connect(ui_.action_NextMdi, SIGNAL(triggered()),
			mdi_area_, SLOT(activateNextSubWindow()));
	connect(ui_.action_PreviousMdi, SIGNAL(triggered()),
			mdi_area_, SLOT(activatePreviousSubWindow()));
	connect(ui_.action_CloseAll, SIGNAL(triggered()),
			mdi_area_, SLOT(closeAllSubWindows()));
	connect(ui_.action_SaveAll, SIGNAL(triggered()),
			this, SLOT(slot_SaveAll()));

	ui_.action_Tile->setWhatsThis( ui_.action_Tile->toolTip() );
	ui_.action_Cascade->setWhatsThis( ui_.action_Cascade->toolTip() );
	ui_.action_NextMdi->setWhatsThis( ui_.action_NextMdi->toolTip() );
	ui_.action_PreviousMdi->setWhatsThis( ui_.action_PreviousMdi->toolTip() );
	ui_.action_CloseAll->setWhatsThis( ui_.action_CloseAll->toolTip() );
	ui_.action_SaveAll->setWhatsThis( ui_.action_SaveAll->toolTip() );
	ui_.menuPanels->setWhatsThis( ui_.menuPanels->toolTip() );

	ui_.action_Tile->setStatusTip( ui_.action_Tile->toolTip() );
	ui_.action_Cascade->setStatusTip( ui_.action_Cascade->toolTip() );
	ui_.action_NextMdi->setStatusTip( ui_.action_NextMdi->toolTip() );
	ui_.action_PreviousMdi->setStatusTip( ui_.action_PreviousMdi->toolTip() );
	ui_.action_CloseAll->setStatusTip( ui_.action_CloseAll->toolTip() );
	ui_.action_SaveAll->setStatusTip( ui_.action_SaveAll->toolTip() );
	ui_.menuPanels->setStatusTip( ui_.menuPanels->toolTip() );

	ui_.action_NextMdi->setShortcuts( QKeySequence::keyBindings( QKeySequence::NextChild ) );
	ui_.action_PreviousMdi->setShortcuts( QKeySequence::keyBindings( QKeySequence::PreviousChild ) );

	/* we need to know when active one changes */
	connect( mdi_area_, SIGNAL( subWindowActivated(QMdiSubWindow*) ),
			 this, SLOT( slot_ActiveMdiChange(QMdiSubWindow*) )
			 );

	/* changing active document using menus */
	connect(ui_.menuPanels, SIGNAL(triggered(QAction*)),
			this,SLOT(slot_ActiveMdiChange(QAction*)));

	/* others */
	slot_UpdateWinMenu();
	slot_ActiveMdiChange( (QMdiSubWindow*)NULL );

	return true;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			MdiImpl::end					( void )
{
	/* stub */
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			MdiImpl::initMenu				( QMenu * menu )
{
	menu->addMenu( ui_.menuPanels );
	menu->addSeparator();
	menu->addAction( ui_.action_Tile );
	menu->addAction( ui_.action_Cascade );
	menu->addSeparator();
	menu->addAction( ui_.action_SaveAll );
	menu->addAction( ui_.action_CloseAll );
	menu->addSeparator();
	menu->addAction( ui_.action_NextMdi );
	menu->addAction( ui_.action_PreviousMdi );

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
EditorBase *				MdiImpl::crtEditor				( void )
{
	MdiContainer * c = static_cast<MdiContainer*>( mdi_area_->currentSubWindow() );
	if ( c == NULL )
		return NULL;

	return c->editor();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool			MdiImpl::closeEvent			( MdiContainer * container )
{
	EditorBase * ed = container->editor();
	if ( ed != NULL )
	{
		return editorCloseReqInternal( ed );
	}
	else
	{
		return true;
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
EditorBase*					MdiImpl::editorForObject	( QObject * o )
{

	if ( o == NULL )
		return NULL;
	QWidget * w = static_cast<QWidget*>( o )->parentWidget();
	if ( w == NULL )
		return NULL;

	Q_ASSERT( w->objectName() == "MdiContainer" );
	return static_cast<MdiContainer*>( w )->editor();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool			MdiImpl::editorCloseReqInternal		( EditorBase * ed )
{
	PGDBG2( PGDBG_MW, "MW: closing document", this );
	PGDBG2( PGDBG_MW, "  - document", ed );

	bool b = true;
	if ( ed == NULL )
	{
		b = true;
	}
	else
	{
		if ( ed->isModified() )
		{
			switch( QMessageBox::question(
						host_->uiParentWidget(),
						tr( "CadPlayG" ),
						tr(
							"The document %1\n"
							"has unsaved changes.\n\n"
							"Save before close?" )
						.arg( ed->documentName() ),
						QMessageBox::Yes |
						QMessageBox::No |
						QMessageBox::Cancel,
						QMessageBox::Yes ) )
			{
			case QMessageBox::Yes:
				if ( ed->isUntitled() )
				{
					b = editorSaveAsReq( ed );
				}
				else
				{
					b = editorSaveReq( ed );
				}
				break;
			case QMessageBox::No:
				b = true;
				break;
			default: /*  QMessageBox::Cancel: */
				b = false;
				break;
			}
		}
		if ( b )
		{
			emit editorClosing( ed );
		}
	}
	return b;

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool			MdiImpl::editorCloseReq		( EditorBase * ed )
{
	if ( ed == NULL )
		return true;

	bool b = editorCloseReqInternal( ed );
	if ( b )
	{
		MdiContainer * c = static_cast<MdiContainer*>(
					ed->asWidget()->parentWidget() );
		c->setEditor( NULL );
		c->close();
		ed->asWidget()->deleteLater();
	}

	return b;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			MdiImpl::editorCreated		( EditorBase * ed )
{
	PGDBG2( PGDBG_MW, "MW: opening document", this );
	PGDBG2( PGDBG_MW, "  - document", ed );

	MdiContainer * mdi_sw;
	mdi_sw = new MdiContainer( this, mdi_area_ );
	mdi_sw->setEditor( ed );

	connect( ed->asWidget(), SIGNAL( openFileUReq(const QString &,const QString &) ),
			 this, SIGNAL( openFileUReq(const QString &,const QString &) )
			 );
	connect( ed->asWidget(), SIGNAL( openLinkUReq(const QUrl &) ),
			 this, SIGNAL( openLinkUReq(const QUrl &) )
			 );
	connect( ed->asWidget(), SIGNAL( outputFileOpened(const QString &) ),
			 this, SLOT( outputFileOpened(const QString &) )
			 );

	slot_UpdateWinMenu();

	mdi_sw->show();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool        				MdiImpl::closeAll              ( void )
{
	QList<QMdiSubWindow*> wins = mdi_area_->subWindowList();
	EditorBase * ed;
	MdiContainer * c;
	foreach( QMdiSubWindow * itr, wins )
	{
		c = static_cast<MdiContainer *>( itr );
		ed = c->editor();
		if ( editorCloseReqInternal( ed ) )
		{
			c->setEditor( NULL );
			c->close();
			ed->asWidget()->deleteLater();
		}
		else
		{
			return false;
		}
	}

	PGDBG( PGDBG_A_MDI, "  - all documents were closed" );
	return true;

}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void        			MdiImpl::slot_ActiveMdiChange    ( QMdiSubWindow * p_active )
{
	PGDBG2( PGDBG_A_MDI, "MdiImpl: active MDI changed by user action", this );
	PGDBG2( PGDBG_A_MDI, "  - to this", p_active );
	PGDBG2( PGDBG_A_MDI, "  - active window",
			mdi_area_->activeSubWindow() );

	for ( ;; )
	{

		slot_UpdateWinMenu();

		QList<QAction *> acls = mdi_area_->actions();
		PGDBG2( PGDBG_A_MDI, "  - actions count", acls.count() );

		QList<QMdiSubWindow*> list = mdi_area_->subWindowList();
		PGDBG2( PGDBG_A_MDI, "  - windows count", list.count() );

		int i = list.indexOf( p_active );
		PGDBG2( PGDBG_A_MDI, "  - window index", i );

		if (i < 0)
			break;
		if (i >= list.count())
			break;
		if (i >= acls.count())
			break;

		PGDBG( PGDBG_A_MDI, "  - index is valid" );

		foreach (QAction *act_m, acls)
		{
			act_m->setChecked(false);
		}
		acls.at( i )->setChecked(true);

		break;
	};

	bool b_with_editor  = ( p_active != NULL );
	if ( b_with_editor )
	{
		MdiContainer * c = static_cast<MdiContainer *>( p_active );
		EditorBase * crt_ed = c->editor();
		emit activeEditorChanged( crt_ed );
	}
	else
	{
		emit activeEditorChanged( NULL );
	}
	ui_.action_Tile->setEnabled( b_with_editor );
	ui_.action_Cascade->setEnabled( b_with_editor );
	ui_.action_NextMdi->setEnabled( b_with_editor );
	ui_.action_PreviousMdi->setEnabled( b_with_editor );
	ui_.action_CloseAll->setEnabled( b_with_editor );
	ui_.action_SaveAll->setEnabled( b_with_editor );
	ui_.menuPanels->setEnabled( b_with_editor );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void        			MdiImpl::slot_ActiveMdiChange    ( QAction * p_active )
{
	PGDBG2( PGDBG_A_MDI, "MdiImpl: active MDI changed by menu", this );
	PGDBG2( PGDBG_A_MDI, "  - with this", p_active );

	QList<QAction *> acls = ui_.menuPanels->actions();
	PGDBG2( PGDBG_A_MDI, "  - actions count", acls.count() );

	QList<QMdiSubWindow*> list = mdi_area_->subWindowList();
	PGDBG2( PGDBG_A_MDI, "  - windows count", list.count() );

	int i = acls.indexOf(p_active);
	PGDBG2( PGDBG_A_MDI, "  - window index", i );

	if (i < 0)
		return;
	if (i >= list.count())
		return;

	PGDBG( PGDBG_A_MDI, "  - index is valid" );

	foreach (QAction *act_m, acls)
	{
		act_m->setChecked( false );
	}

	p_active->setChecked( true );
	mdi_area_->setActiveSubWindow( list.at(i) );
	slot_ActiveMdiChange( list.at(i) );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void					MdiImpl::outputFileOpened		( const QString & s )
{
	Q_UNUSED( s );
	/* stub */
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool        			MdiImpl::slot_SaveAll		    (void)
{
	PGDBG2( PGDBG_A_MDI, "MW_BasicSlots: save all", this );
	bool b;


	QList<QMdiSubWindow*> wins = mdi_area_->subWindowList();
	PGDBG2( PGDBG_A_MDI, "  - opened documents:", wins.count() );

	EditorBase * ed;
	MdiContainer * c;
	foreach( QMdiSubWindow * itr, wins )
	{
		c = static_cast<MdiContainer*>( itr );
		ed = c->editor();
		PGDBG2( PGDBG_A_MDI, "  - document:", ed );

		if ( ed->isModified() )
		{
			PGDBG( PGDBG_A_MDI, "    - modified" );
			if ( ed->isUntitled() )
			{
				b = editorSaveAsReq( ed );
			}
			else
			{
				b = editorSaveReq( ed );
			}
			if ( b == false )
			{
				return false;
			}
		}
	}
	return true;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool					MdiImpl::editorSaveAsReq		( EditorBase * ed )
{
	PGDBG2( PGDBG_MW, "MW: saving document as", this );
	PGDBG2( PGDBG_MW, "  - document", ed );

	if ( ed == NULL )
	{
		QMessageBox::warning( host_->uiParentWidget(), tr( "Error saving file" ),
							  tr( "There is no file to save" ), QMessageBox::Ok );
		return false;
	}

	QFileDialog::Options options;
	QString			selectedFilter = "*.htmlit";
	QString &		s_dir_crt = host_->crtDirectory();
	QString s_dir_to_use = ed->filePath();
	if ( s_dir_to_use.isEmpty() )
	{
		s_dir_to_use = s_dir_crt;
	}
	QString s_file = QFileDialog::getSaveFileName(
				host_->uiParentWidget(),
				tr("Select the location of the file..."),
				s_dir_to_use,
				tr("cad-play-ground files (*.cpg);;All Files (*)"),
				&selectedFilter,
				options );
	PGDBG2( PGDBG_MW, "  - choice", s_file );

	if ( !s_file.isEmpty() )
	{
		QFileInfo	fi( s_file );

		/* save the directory that we last browsed to */
		s_dir_crt = fi.absolutePath();

		/* if the file has no extension, default to .htmlit */
		if ( fi.fileName().contains( '.' ) == false )
		{
			s_file = fi.absoluteDir().absoluteFilePath( fi.fileName() + ".htmlit" );
		}

		/* attempt to save */
		if ( ed->fileSave( s_file ) == false )
		{
			QMessageBox::warning( host_->uiParentWidget(), tr( "CadPlayG" ),
								  tr( "Error saving file" ) );
			return false;
		}

		PGDBG2( PGDBG_MW, "  - saved; name ", ed->documentName() );
		PGDBG2( PGDBG_MW, "  - title ", ed->asWidget()->windowTitle() );

		ed->asWidget()->parentWidget()->setWindowTitle( ed->asWidget()->windowTitle() );
		ed->asWidget()->parentWidget()->setWindowModified( false );

		/* let the outer world know the event */
		emit editorSaved( ed );
		slot_editorSaved( ed );
		return true;
	}
	return false;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool					MdiImpl::editorSaveReq			( EditorBase * ed )
{
	PGDBG2( PGDBG_MW, "MW: saving document", this );
	PGDBG2( PGDBG_MW, "  - document", ed );

	if ( ed == NULL )
	{
		QMessageBox::warning( host_->uiParentWidget(), tr( "Error saving file" ),
							  tr( "There is no file to save" ), QMessageBox::Ok );
		return false;
	}

	if ( ed->isUntitled() )
	{
		PGDBG2( PGDBG_MW, "  - new / url", ed->documentName() );
		return editorSaveAsReq( ed );
	}
	else if ( ed->fileSave() == false )
	{
		QMessageBox::warning( host_->uiParentWidget(), tr( "CadPlayG" ),
							  tr( "Error saving file" ), QMessageBox::Ok );
		return false;
	}
	else
	{
		PGDBG2( PGDBG_MW, "  - saved; name ", ed->documentName() );
		PGDBG2( PGDBG_MW, "  - title ", ed->asWidget()->windowTitle() );

		ed->asWidget()->parentWidget()->setWindowTitle( ed->asWidget()->windowTitle() );
		ed->asWidget()->parentWidget()->setWindowModified( false );

		/* let the outer world know the event */
		emit editorSaved( ed );
		slot_editorSaved( ed );
		return true;
	}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void        			MdiImpl::slot_UpdateWinMenu      (void)
{
	PGDBG2( PGDBG_A_MDI, "			MdiImpl: updating window menu", this );

	ui_.menuPanels->clear();

	QList<QMdiSubWindow *> windows = mdi_area_->subWindowList();
	PGDBG2( PGDBG_A_MDI, "  - windows count", windows.count() );

	if ( windows.count() == 0 )
	{
		PGDBG( PGDBG_A_MDI, "  - no windows" );
		ui_.menuPanels
				->addAction( tr( "(none)" ) )
				->setEnabled( false );
		return;
	}

	PGDBG2( PGDBG_A_MDI, "  - active window",
			mdi_area_->activeSubWindow() );
	QString s_label;
	QAction * action;
	EditorBase * ed;
	MdiContainer * c;
	for ( int i = 0; i < windows.count(); ++i )
	{
		c = static_cast<MdiContainer *>( windows.at( i ) );
		ed = c->editor();
		if ( ed != NULL )
		{
			if ( i < 9 )
			{
				s_label = tr("&%1 %2").arg(i + 1).arg( ed->documentName() );
			}
			else
			{
				s_label = tr("%1 %2").arg(i + 1).arg( ed->documentName() );
			}
			action = ui_.menuPanels->addAction( s_label );
			action->setCheckable( true );
			action->setChecked( windows.at( i ) == mdi_area_->activeSubWindow() );
		}
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			MdiImpl::slot_editorSaved		( EditorBase * ed )
{
	QWidget * w = ed->asWidget();
	MdiContainer * c = static_cast<MdiContainer*>( w->parentWidget() );
	c->setWindowTitle( w->windowTitle() );
	c->setWindowModified( ed->isModified() );

}
/* ========================================================================= */


/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
